
#define _GNU_SOURCE
#include "App_Serial.h"

// 设置波特率
int App_Serial_SetBaudRate(Device_t *device, BaudRate baudRate)
{
    //  读取串口属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    //  修改属性
    cfsetispeed(&attr, baudRate);
    //  设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr); // 设置为稍后修改串口属性
    if (result != 0)
    {
        log_error("设置串口波特率失败");
        return -1;
    }
    log_debug("设置串口波特率成功");
    return 0;
}

// 设置校验位
int App_Serial_SetPartity(Device_t *device, Parity parity)
{
    // 读取串口属性
    struct termios attr; // 定义串口属性结构体
    tcgetattr(device->fd, &attr);

    // 修改属性
    attr.c_cflag &= ~(PARENB | PARODD); // 清除校验位
    attr.c_cflag |= parity;             // 设置校验位

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("设置串口校验位失败");
        return -1;
    }
    log_debug("设置串口校验位成功");
    return 0;
}

// 设置停止位
int App_Serial_SetStopBits(Device_t *device, StopBits stopBits)
{
    // 读取串口属性
    struct termios attr; // 定义串口属性结构体
    tcgetattr(device->fd, &attr);

    // 修改属性
    attr.c_cflag &= ~CSTOPB;  // 清除停止位
    attr.c_cflag |= stopBits; // 设置停止位

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("设置串口停止位失败");
        return -1;
    }
    log_debug("设置串口停止位成功");
    return 0;
}

// 设置阻塞模式
int App_Serial_SetBlock(Device_t *device, int is_block)
{
    // 读取串口属性
    struct termios attr; // 定义串口属性结构体
    tcgetattr(device->fd, &attr);

    // 修改属性
    if (is_block)
    {
        // 阻塞模式
        attr.c_cc[VMIN] = 1;  // 至少要读取一个字节才会返回
        attr.c_cc[VTIME] = 0; // 没等到数据会一直等待
    }
    else
    {
        // 非阻塞模式
        attr.c_cc[VMIN] = 0;  // 没有读取到数据也是会返回
        attr.c_cc[VTIME] = 2; // 单位100ms,就是当前等待200ms/0.2s才会返回
    }

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("设置串口阻塞模式失败");
        return -1;
    }
    log_debug("设置串口阻塞模式成功");
    return 0;
}

// 设置原始模式
int App_Serial_SetRaw(Device_t *device)
{
    // 读取串口属性
    struct termios attr; // 定义串口属性结构体
    tcgetattr(device->fd, &attr);

    // 修改属性
    cfmakeraw(&attr); // 设置为原始模式

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("设置串口原始模式失败");
        return -1;
    }
    log_debug("设置串口原始模式成功");
    return 0;
}

// 初始化
int App_Serial_Init(Device_t *device)
{
    // 设置各个属性
    App_Serial_SetBaudRate(device, BR_9600);
    App_Serial_SetPartity(device, Parity_None);
    App_Serial_SetStopBits(device, SB_1);
    // App_Serial_SetBlock(device,0); 此处不生效
    App_Serial_SetRaw(device);

    // 让属性生效
    int result = tcflush(device->fd, TCIOFLUSH);
    if (result != 0)
    {
        log_error("初始化串口失败");
        return -1;
    }
    log_debug("初始化串口成功");
    return 0;
}

// 刷新串口输入输出缓冲区
// 功能：清除串口未读取的输入数据和未发送的输出数据，避免旧数据干扰后续通信
// 参数：
//   device - 指向设备结构体的指针，包含串口文件描述符信息
int App_Serial_Flush(Device_t *device) {
    // 调用tcflush清空缓冲区，TCIOFLUSH表示同时刷新输入缓冲区(TCIOFLUSH = TCIFLUSH | TCOFLUSH)
    tcflush(device->fd, TCIOFLUSH);
}